﻿using FPSO.HMI.Controls;
using FPSO.HMI.Utils;
using FPSO.HMI.Views.Dialog;
using FPSO.Models.Constant;
using FPSO.Models.Domain;
using FPSO.Models.TagMapping;
using FPSO.Services;
using FPSO.Services.Impl;
using NSubstitute.Core;
using SafeLoad.NControl.Assist;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Threading;

namespace FPSO.HMI.Views
{
    /// <summary>
    /// TaskManageView.xaml 的交互逻辑
    /// </summary>
    public partial class TaskManageView : UserControl
    {
        private DateTime currentTime = DateTime.MinValue;
        private DateTime MaxTime = DateTime.MinValue;
        private DispatcherTimer taskTimer = null;
        private DateTime endTime = DateTime.MinValue;
        private DateTime lastReflushTime = DateTime.MinValue;
		private Dictionary<string, double> currentVolmDic = new Dictionary<string, double>();
		private Dictionary<string, double> currentRateDic = new Dictionary<string, double>();
        private List<string> haveShowTaskIds = new List<string>();
        private TaskTankCalcService taskTankCalcService = null;
        //Thread taskThread = null;
        bool running = false;
        bool bPause = false;

		//DEBUG 控制界面的刷新时间和每次刷新对应的实际时间间隔
		private int m_UpdateTimeGap = 500; //Milliseconds
		private int m_SimuTimeGap = 5; //mins

		private Dictionary<string, double> ori_TankVolumes = new Dictionary<string, double>();

		//保存待执行的舱室调载任务
		private List<TankTask> taskList = new List<TankTask>();
        public TaskManageView()
        {
            InitializeComponent();

			taskQueue.TaskService = new DBTankTaskService();

            taskTankCalcService = new TaskTankCalcService(taskQueue.TaskService);

			taskTimer = new DispatcherTimer();

			initCurve();

			foreach (KeyValuePair<string, double> kvp in oilBallast.GetTankVolumeDic())
			{
				ori_TankVolumes.Add(kvp.Key, kvp.Value);
			}

			initTankVolumeForImitate(ori_TankVolumes);
		}

		//DEBUG 这里用于当前舱室状态初始化
        public void initTankVolumeForImitate(Dictionary<string,double> tankvols)
        {
            oilBallast.initTankVolumeForImitate(tankvols);
			//outAndSwap.initTankVolumeForImitate();
		}

		public void initCurve()
		{
			// 强度
			str_CurveLine.SetCurve("剪力", null, Colors.DodgerBlue);
			str_CurveLine.SetCurve("弯矩", null, Colors.DarkOrange);
			// 舯吃水
			tm_CurveLine.SetCurve("计算舯吃水", null, Colors.DodgerBlue);
			// 横纵倾
			dra_CurveLine.SetCurve("横倾", null, Colors.DodgerBlue);
			dra_CurveLine.SetCurve("纵倾", null, Colors.DarkOrange);
			// 初稳性高
			sta_CurveLine.SetCurve("初稳性高", null, Colors.DodgerBlue);
		}
		private void TaskQueue_AddTaskAction(object button, int queueId)
        {
            /*
            //以当前时间为起点，计算当前各舱状态
            oilBallast.StartImitate();
            outAndSwap.StartImitate();
			DateTime dateTime0 = DateTime.Now;
			oilBallast.SetImitateTime(dateTime0);
			outAndSwap.SetImitateTime(dateTime0);
			Dictionary<string, double> currentVolmDic0 = oilBallast.GetTankVolumeDic();

			DBTankTaskService dBTankTaskService = new DBTankTaskService();
			taskList = dBTankTaskService.GetAllWaitAndExecingAndCheckingTaskList();

			SafeLoadAlgorithmService algorithmService = SafeLoadAlgorithmService.GetInstance();

			foreach (TankTask task in taskList)
			{
				DateTime planfromtime = task.PlanStartTime;
				oilBallast.SetImitateTime(planfromtime);
				Dictionary<string, double> fromVolmDic = oilBallast.GetTankVolumeDic();
				ManualCalcResult calcResult = algorithmService.CallManualCalc(fromVolmDic, 3);  //待测试，CallManualCalc->CallManualCalcA，用于模拟演示

				DateTime planendtime = task.PlanEndTime;
				oilBallast.SetImitateTime(planendtime);
				Dictionary<string, double> endVolmDic = oilBallast.GetTankVolumeDic();
				calcResult = algorithmService.CallManualCalc(endVolmDic, 3);
				double a = 0;
			}
            */
            // 鉴权操作
            if (!AuthUtil.IsHasPermission())
            {
                return;
            }
            TaskInfoView createView = new TaskInfoView(queueId, new DBTankTaskService());
            try { createView.ShowDialog(); } catch (Exception ex) { return; }


            //List<TankTask> cotlist = createView.waitTaskList;
            //List<WBTTask> wbtlist = createView.wTaskList;
        }

        private void TaskQueue_PauseTaskAction(object button, int queueId)
        {
            taskTimer.Stop();
            bPause = true;
        }

        private void TaskQueue_SubmitTaskAction(object button, int queueId)
        {
            // 鉴权操作
            if (!AuthUtil.IsHasPermission())
            {
                return;
            }
            DBTankTaskService dBTankTaskService = new DBTankTaskService();
            taskList = dBTankTaskService.GetAllWaitingAndCheckingTaskList();
            //Debug 任务列表获取失败，待排查
            if (null == taskList)
            {
                MessageBox.Show("获取所有通过校核、等待执行的任务失败，获取结果为：NULL");
                return;
            }
            foreach (TankTask task in taskList)
            {
                task.TaskState = TaskStateConstant.WATING_ID;
                dBTankTaskService.UpdateTask(task);
            }
            MessageBox.Show("提交完成");
        }

        private void taskQueue_StartImitateAction(object obj)
        {

			if (bPause)
            {
                taskTimer.Start();
				bPause = false;
            }

            haveShowTaskIds.Clear();
            DBTankTaskService dBTankTaskService = new DBTankTaskService();
            taskList = dBTankTaskService.GetAllWaitAndExecingAndCheckingTaskList();
			if(taskList.Count > 0)
			{
				initTankVolumeForImitate(ori_TankVolumes);

				TankTask task = taskList[0];
				currentTime = task.PlanStartTime;
				//点启动后再启动计时
				taskTimer.Interval = TimeSpan.FromMilliseconds(m_UpdateTimeGap);
				taskTimer.Tick += TaskTimer_Tick;
				taskTimer.Start();

				List<TaskTankTimeFlagDetail> res = taskTankCalcService.GetAllTaskTankDetails(null);

				currentTime = res[0].TimeFlag;
				endTime = res[res.Count - 1].TimeFlag;
				MaxTime = currentTime.AddHours(120);
				lastReflushTime = currentTime;

				oilBallast.StartImitate();
				outAndSwap.StartImitate();
			}
		}

        private void TaskQueue_AutoTaskAction(object button, int queueId)
        {
            // 鉴权操作
            if (!AuthUtil.IsHasPermission())
            {
                return;
            }
            //在这里调用自动生成任务的接口
            //以当前时间为起点，计算当前各舱状态
            oilBallast.StartImitate();
			outAndSwap.StartImitate();

			//DEBUG 找到当前数据库中最晚结束的一个任务
			DBTankTaskService dBTankTaskService = new DBTankTaskService();
            //Debug 任务列表获取失败，待排查
            List<TankTask> taskList = dBTankTaskService.GetAllWaitAndExecingAndCheckingTaskList();
            if (null == taskList)
            {
                MessageBox.Show("获取通过校核、等待执行、正在执行的任务失败，获取结果为：NULL");
                return;
            }
            DateTime dateTime0 = DateTime.Now;
			foreach (TankTask task in taskList)
			{
				if(dateTime0 < task.PlanEndTime)
				{
					dateTime0 = task.PlanEndTime;
				}
			}
			oilBallast.SetImitateTime(lastReflushTime,dateTime0);

			//DEBUG现在装卸载和倒舱的任务区别是什么？
			//outAndSwap.SetImitateTime(dateTime0);
			Dictionary<string, double> currentVolmDic0 = oilBallast.GetTankVolumeDic();

			//下面这段是否可以跳过
			//Dictionary<string, double> taskTankVolume = taskTankCalcService.GetAllTankVolume(currentVolmDic0,null);

			Dictionary<string, double> taskTankVolume = currentVolmDic0;

			SafeLoadAlgorithmService algorithmService = SafeLoadAlgorithmService.GetInstance();

			ManualCalcResult calcResult = algorithmService.CallAutoCalc(taskTankVolume, 3);
			//ManualCalcResult calcResult = algorithmService.CallManualTest(taskTankVolume);

			if (calcResult == null)
            {
                MessageBox.Show("服务端接口调用失败", "提示");
                return;
            }

            TankTask tankTask = buildTaskByCalcResult(calcResult,1, taskTankVolume);
            TaskInfoView createView = new TaskInfoView(queueId, new DBTankTaskService());
            createView.InitTaskConent(tankTask);

            createView.ShowDialog();
        }

        private void fillTankTaskByCOT(TankCalcState cot,TankTask task, Dictionary<string, double> taskTank)
        {
            task.TaskName = string.Empty;
            task.TankId = cot.Abname;
			double initVolm = taskTank[cot.Abname];
			if (initVolm > cot.Volume) 
				task.TaskType = TaskTypeConstant.UNLOAD_ID;
            else if (initVolm < cot.Volume) 
				task.TaskType = TaskTypeConstant.LOAD_ID;

            task.TaskState = TaskStateConstant.CHECK_ID;
            task.TaskResult = TaskResultConstant.UNEXEC_ID;

            TankTask preTask = taskTankCalcService.getPreTask(1);

            if (preTask != null)
            {
                task.PreTaskId = preTask.TaskId;
                task.StartType = TaskStartTypeConstant.START_BY_QUEUE_ID;
                task.PlanStartTime = preTask.PlanEndTime;
            }
            else
            {
                task.StartType = TaskStartTypeConstant.START_BY_TIME_ID;
                task.PlanStartTime = DateTime.Now;
            }

            DateTime planEndTime = task.PlanStartTime;
            task.PlanEndTime = planEndTime.AddHours( Math.Abs(cot.Volume- taskTank[cot.Abname]) / 1500);
            task.TargetVolm = Convert.ToInt32(cot.Full);


			SafeLoadAlgorithmService safeloadAlgorithm = SafeLoadAlgorithmService.GetInstance();
			//Tips：C++端接口新增SingleTank计算方法，每次仅支持单一舱室的计算，详见《C++端接口调用说明》
			string cotName = TankConstant.GetTankName(cot.Abname);
			string inputstr = "{Manual}#{volume}#{" + string.Join("#", cotName, initVolm.ToString() + "#}");
			ManualCalcResult result = safeloadAlgorithm.CallPipeSingleCalc(inputstr, cot.Abname);
			if (result != null)
			{
				//Tips：其余控件赋值来源于接口计算结果
				TankCalcState tankState = result.GetTankCalcState(cot.Abname);
				task.InitVolm = tankState.Full;
			}			
		}

        private void fillTankTaskByWBT(TankCalcState wbt, TankTask task, Dictionary<string, double> taskTank)
        {
			double initVolm = taskTank[wbt.Abname];
			SafeLoadAlgorithmService safeloadAlgorithm = SafeLoadAlgorithmService.GetInstance();
			//Tips：C++端接口新增SingleTank计算方法，每次仅支持单一舱室的计算，详见《C++端接口调用说明》
			string wbtName = TankConstant.GetTankName(wbt.Abname);
			string inputstr = "{Manual}#{volume}#{" + string.Join("#", wbtName, initVolm.ToString() + "#}");
			ManualCalcResult result = safeloadAlgorithm.CallPipeSingleCalc(inputstr, wbt.Abname);
			if (result != null)
			{
				//Tips：其余控件赋值来源于接口计算结果
				TankCalcState tankState = result.GetTankCalcState(wbt.Abname);
				task.WBTTaskList.Add(new WBTTask()
				{
					WBTTankId = wbt.Abname,
					PipeSpeed = task.PipeSpeed,
					TargetVolume = wbt.Full,
					InitVolume = tankState.Full,
					IsLoad = wbt.Volume > taskTank[wbt.Abname]
				});
			}
        }
        private TankTask buildTaskByCalcResult(ManualCalcResult res,int taskQueue,Dictionary<string, double> taskTank)
        {
            TankTask task = new TankTask();
            task.TaskQueueId = taskQueue;
            task.SwapTargetTank1 = "";
            task.TankId = "";
            task.TargetVolm = 0;
            task.PipeSpeed = 1500;
            task.ExecStartTime = DateTime.MinValue;
            task.ExecEndTime = DateTime.MinValue;
            task.CreateTime = DateTime.Now;
            task.UpdateTime = DateTime.Now;
            task.DeleteTime = DateTime.MinValue;

            foreach (TankCalcState state in res.tankCalcStates)
            {
                if (state.Density == 0 && state.Inn == 0) continue;

                if(state.Abname.IndexOf("COT") >= 0)
                {
                    fillTankTaskByCOT(state,task, taskTank);
                }
                if (state.Abname.IndexOf("WBT") >= 0)
                {
                    fillTankTaskByWBT(state, task, taskTank);
                }
            }
            return task;
        }

        public void ReloadTaskQueue()
        {
            taskQueue.ControlUpdate();
        }

        private void TaskTimer_Tick(object sender, EventArgs e)
        {
			//进入线程后，先检查任务对应的设备状态，确定后方可开始模拟过程
			foreach (TankTask task in taskList)
			{
				if (currentTime >= task.PlanStartTime)
				{
					if (!haveShowTaskIds.Contains(task.TankId))
					{
						haveShowTaskIds.Add(task.TankId);
						TaskTankCheckDialog taskTankCheckDialog = new TaskTankCheckDialog(task);
						if (taskTankCheckDialog.ShowDialog() == true)
						{
							running = true;
						}
					}
				}
			}
			if(running == false)
			{
				taskTimer.Stop();
				taskQueue.setClickBackground(running);
				MessageBox.Show("设备状态与设定状态不符", "模拟提示");
				return;
			}

			if (currentTime != DateTime.MinValue)  //待测试，暂时封掉
            {
				//每隔500ms刷新一次，每次时间快进2min，后期需要改为可调整的
				//currentTime = currentTime.AddMinutes(m_SimuTimeGap);

				currentTime = currentTime.AddSeconds(m_SimuTimeGap);
				taskQueue.CurrentTime = currentTime;
                oilBallast.SetImitateTime(lastReflushTime,currentTime);
                outAndSwap.SetImitateTime(lastReflushTime,currentTime);

                //if (currentVolmDic.Count == 0)
				{
					currentVolmDic = oilBallast.GetTankVolumeDic();
				}

				Dictionary<string, double> newVolmDic = currentVolmDic;
				//DEBUG 上面currentVolmDic已经算出当前各舱装载体积，下面这一段的意义是什么？
				/*Dictionary<string, double> newVolmDic = new Dictionary<string, double>();
                foreach (TankTask task in taskList)
                {
                    string tankid = task.TankId;
                    double pipespeed = task.PipeSpeed;
                    double cotvol = currentVolmDic[tankid];
                    cotvol += addmin / 60 * pipespeed;

                    if (!newVolmDic.ContainsKey(tankid))
                    {
                        newVolmDic.Add(tankid, cotvol);
                    }
                    else
                    {
                        newVolmDic[tankid] = cotvol;
                    }

                    List<WBTTask> wbttasklist = task.WBTTaskList;
                    foreach (WBTTask wbttask in wbttasklist)
                    {
                        string bwtid = wbttask.WBTTankId;
                        double wbtPipeSpeed = wbttask.PipeSpeed;
                        bool isload = wbttask.IsLoad;
                        if (!isload)
                            wbtPipeSpeed = -wbtPipeSpeed;
                        double bwtvol = currentVolmDic[bwtid];
                        bwtvol += addmin / 60 * wbtPipeSpeed;
                        if (!newVolmDic.ContainsKey(bwtid))
                        {
                            newVolmDic.Add(bwtid, bwtvol);
                        }
                        else
                        {
                            newVolmDic[bwtid] = bwtvol;
                        }
                    }
                }*/

				if (currentTime > MaxTime)
                {
                    currentTime = DateTime.MinValue;
                    MaxTime = DateTime.MinValue;
                }

                if(lastReflushTime > endTime)
                {
                    currentTime = DateTime.MinValue;
                    MaxTime = DateTime.MinValue;
                    taskTimer.Stop();
                    MessageBox.Show("模拟装载完成", "模拟提示");
                }

                SafeLoadAlgorithmService algorithmService = SafeLoadAlgorithmService.GetInstance();
                //ManualCalcResult calcResult = algorithmService.CallManualCalcA(newVolmDic, time);  //待测试，CallManualCalc->CallManualCalcA，用于模拟演示
                ManualCalcResult calcResult = algorithmService.CallManualCalc(newVolmDic, 3);  //待测试，CallManualCalc->CallManualCalcA，用于模拟演示
                
                if (calcResult != null)
                {
                    //待测试，这里直接用计算结果为控件赋值
                    oilBallast.ReflushViewModel(calcResult);
                    outAndSwap.ReflushViewModel(calcResult);
                    ShipDraught calcDraught = calcResult.GetCalcDraught();

					AddCurveData(DateTime.Now, calcResult.ShipCalc);

					currentVolmDic = newVolmDic;
                }

				lastReflushTime = lastReflushTime.AddSeconds(m_SimuTimeGap);

				//lastReflushTime.AddMinutes(m_SimuTimeGap);

                if (lastReflushTime > MaxTime)
                {
                    taskTimer.Stop();
                }
            }
        }

        public void AddCurveData(DateTime curTime, ShipCalcState shipCalc)
        {
			this.Dispatcher.Invoke(new Action(() => 
			{
				str_CurveLine.AddCurveData(new string[] { "剪力", "弯矩" }, new double[] { shipCalc.MaxPersf, shipCalc.MaxPerbm });
				tm_CurveLine.AddCurveData(new string[] { "计算舯吃水" }, new double[] { shipCalc.TM });
				dra_CurveLine.AddCurveData(new string[] { "横倾", "纵倾" }, new double[] { shipCalc.Heel, shipCalc.Trim });

				if (Math.Abs(shipCalc.GM) < 20)
				{
					sta_CurveLine.AddCurveData(new string[] { "初稳性高" }, new double[] { shipCalc.GM });
				}
			}));
        }

		private void TaskQueue_DefineStatusAction(object arg1, int arg2)
		{
			//功能更新，此处需通过设置对话框输入
			Dictionary<string, double> currentVolmDic0 = oilBallast.GetTankVolumeDic();
			Dictionary<string, double> currentVolmDic_new = new Dictionary<string, double>();

			double newvalue = 50;
			foreach (KeyValuePair<string, double> kvp in currentVolmDic0)
			{
				double new_value = newvalue;
				currentVolmDic_new.Add(kvp.Key, new_value);
				newvalue += 10.0;
			}
			ori_TankVolumes = currentVolmDic_new;
			currentVolmDic0 = currentVolmDic_new;
			initTankVolumeForImitate(ori_TankVolumes);
		}

		private TankMonitorDialog tankMonitorDialogInstance;
		private void TankMonitorButton_Click(object sender, RoutedEventArgs e)
		{
			if (tankMonitorDialogInstance == null || !tankMonitorDialogInstance.IsVisible)
			{
				tankMonitorDialogInstance = new TankMonitorDialog();
				tankMonitorDialogInstance.Closed += TankMonitorDialogClosed;
				tankMonitorDialogInstance.Show();
			}
			else
			{
				// 如果窗口已经可见，可以选择将其激活
				tankMonitorDialogInstance.Activate();
			}
		}
		private void TankMonitorDialogClosed(object sender, EventArgs e)
		{
			// 窗口关闭时，将实例设置为 null，以便可以再次创建
			tankMonitorDialogInstance = null;
		}
	}
}
